#include <opencv2/highgui/highgui.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/opencv.hpp>
#include <iostream>
#include <time.h>
#include <vector>

using namespace std;
using namespace cv;


// 第一个参数是图片，第二个参数和第三个参数是对用的参数，建议0.5，0.5基本就可以应对大多数的情况了
// 采用的是自动色阶的算法，很多是在网上白嫖的，运行速度目前来看还算可以
Mat autolevel(Mat matface,double dlowcut,double dhighcut)
{
    
	uchar allmap[256*3] = {0};
	//double dlowcut = 0.5;
	//double dhighcut = 0.5;

	long T_1 = clock();
	vector<Mat> rgb_planes;
	split(matface,rgb_planes);
	Mat HistBlue,HistGreen,HistRed;
	int histSize = 256;
	float range[] = { 0, 255 } ;
	const float* histRange = { range };
	bool uniform = true; bool accumulate = false;
    
	calcHist( &rgb_planes[0], 1, 0, Mat(), HistRed, 1,&histSize, &histRange, uniform, accumulate );
	calcHist( &rgb_planes[1], 1, 0, Mat(), HistGreen, 1, &histSize, &histRange, uniform, accumulate );
	calcHist( &rgb_planes[2], 1, 0, Mat(), HistBlue, 1, &histSize, &histRange, uniform, accumulate );
	printf("\n hist time %f ms.\n",(double)(clock() - T_1));

	int PixelAmount = matface.rows*matface.cols;
	//printf("%d\n",PixelAmount);
	float isum = 0;
	// blue

	long T_2 = clock();
	int iminblue=0;int imaxblue=0;

	for (int y = 0;y<256;y++)
	{
		isum= isum + HistBlue.at<const float>(y);

		if (isum>=PixelAmount*dlowcut*0.01)
		{
			iminblue = y;
			break;
		}
	}

	isum = 0;

	for (int y=255;y>=0;y--)
	{
		isum=isum + HistBlue.at<const float>(y);

		if (isum>=PixelAmount*dhighcut*0.01)
		{
			imaxblue=y;
			break;
		}
	}
	isum=0;
	int iminred=0;int imaxred=0;

	for (int y = 0;y<256;y++)
	{
		isum= isum+HistRed.at<const float>(y);

		if (isum>=PixelAmount*dlowcut*0.01)
		{
			iminred = y;
			break;
		}
	}

	isum = 0;

	for (int y=255;y>=0;y--)
	{
		isum=isum+HistRed.at<const float>(y);

		if (isum>=PixelAmount*dhighcut*0.01)
		{
			imaxred=y;
			break;
		}
	}

	isum=0;
	int imingreen=0;int imaxgreen=0;

	for (int y = 0;y<256;y++)
	{
		isum= isum+HistGreen.at<const float>(y);
		if (isum>=PixelAmount*dlowcut*0.01)
		{
			imingreen = y;
			break;
		}
	}

	isum = 0;

	for (int y=255;y>=0;y--)
	{
		isum=isum+HistGreen.at<const float>(y);

		if (isum>=PixelAmount*dhighcut*0.01)
		{
			imaxgreen=y;
			break;
		}
	}
	printf("\n cut time %f ms.\n",(double)(clock() - T_2));

	long T_3 = clock();
#pragma omp parallel for 
	for (int y=0;y<256;y++)
	{
		if (y<=iminblue)
		{
			allmap[y*3+2]=0;
		}
		else
		{
			if (y>imaxblue)
			{
				allmap[y*3+2]=255;
			}
			else
			{
				float ftmp = (float)(y-iminblue)/(imaxblue-iminblue);
				allmap[y*3+2]=(uchar)(ftmp*255);
			}
		}

	}
	//red
#pragma omp parallel for 
	for (int y=0;y<256;y++)
	{
		if (y<=iminred)
		{
			allmap[y*3]=0;
		}
		else 
		{
			if (y>imaxred)
			{
				allmap[y*3]=255;
			}
			else
			{
				float ftmp = (float)(y-iminred)/(imaxred-iminred);
				allmap[y*3]=(uchar)(ftmp*255);
			}
		}

	}
	//green
#pragma omp parallel for 
	for (int y=0;y<256;y++)
	{
		if (y<=imingreen)
		{
			allmap[y*3+1]=0;
		}
		else 
		{
			if (y>imaxgreen)
			{
				allmap[y*3+1]=255;
			}
			else
			{
				float ftmp = (float)(y-imingreen)/(imaxgreen-imingreen);
				allmap[y*3+1]=(uchar)(ftmp*255);
			}
		}

	}
	printf("\n map time %f ms.\n",(double)(clock() - T_3));

	long T_4 = clock();
	Mat lut(1,256,CV_8UC3,allmap);
	LUT(matface,lut,matface);
	printf("\n values time %f ms.\n",(double)(clock() - T_4));

	return matface;
}

int main()
{
	VideoCapture video;
	video.open(0);

	Mat I;
	while (true)
	{
		video>>I;
		long T_1 = clock();
		cv::resize(I, I, cv::Size(512, 512), (0, 0), (0, 0), cv::INTER_LINEAR);
		Mat dehaze = autolevel(I,0.9,0.9);
		printf("\nTotal Time: %f ms.\n", (double)(clock() - T_1)); 

		namedWindow("dehaze",WINDOW_NORMAL);
		imshow("dehaze",dehaze);
		waitKey(1);

	}

	return 0;
}
